#include "utils.h"
#include "config.h"
#include "uvlog.h"

#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/sendfile.h>


//#define MAX_PATH_LEN 255
//#define VERSION "1.0"
/**
modified at 2010-09-14
add delete file cmd
modified at 2010-09-20
support empty file transfer
*/
#define VERSION "1.0"

volatile int stop = 0;

volatile int Utils::timerFlag = 0;
int background = 1;
	
int Utils::fdinfo(int fd,char* ip,unsigned short& port)
{
	struct sockaddr_in address;
	socklen_t addrLen = sizeof(address);
	struct sockaddr* socketAddress = reinterpret_cast<sockaddr*>(&address);

	int error = getpeername(fd, socketAddress, &addrLen);
	if(error)
	{
		return error;
	}

	strncpy(ip,inet_ntoa(address.sin_addr),20);
	port = ntohs(address.sin_port);


	return 0;
}

static void sigterm_handler(int signo) {    
	LOG_INFO("be stoped by signal:%d",signo);    
	stop = 1;
}

/*
static void showVersion (int argc,char** argv){	
	printf("%s v%s build on %s %s\n",argv[0], VERSION,__DATE__,__TIME__);
}


static void showUsage (int argc,char** argv){	
	showVersion(argc,argv);	
	printf("Usage:\n    %s [-d] [-f config/common.conf] \n", argv[0]);
}

static int checkConfig(const char* confFile){
	CConfig *pConfig = CConfig::getInstance();

	if(pConfig->ParseConfig(confFile) != 0){
		fprintf(stderr,"parse config file %s failed,may be format error or not exist,%m\n",confFile);
		return -1;
	}

	const char* logFName = pConfig->GetStrVal("LOG","FlowLog");
	if(logFName == NULL){
		fprintf(stderr,"config file must contain [LOG] FlowLog\n");
		return -1;
	}

	int size = pConfig->GetIntVal("LOG","FlowLogSize",100);
	int count = pConfig->GetIntVal("LOG","FlowLogCount",10);

	INIT_LOG(logFName,size*1024*1024,count);

	if(g_pLog == NULL){
		fprintf(stderr,"flow log init failed:%m\n");
		return -1;
	}

	g_pLog->setLogLevel(pConfig->GetIntVal("LOG","LogMode",6));

	
	return 0;
}
*/

int Utils::daemonInit(int argc,char** argv){

	/*
	int c;

	char confFile[100] = {0};
	char dumpFile[100] = {0};
	bool dumpFlag = false;
	while ((c = getopt (argc, argv, "df:o:hv")) != -1) {		
		switch (c) {		
			case 'd':			
				background = 0;			
				break;		
			case 'f':			
				strncpy (confFile, optarg, sizeof (confFile) - 1);			
				break;
			case 'o':
				strncpy (dumpFile, optarg, sizeof (dumpFile) - 1);
				dumpFlag = true;
				break;
			case 'h':			
				showUsage (argc,argv);			
				exit(0);		
			case 'v':			
				showVersion (argc,argv);			
				exit(0);		
			case '?':			
				showUsage (argc,argv);			
				exit(-1);		
			}
	}

	if(strlen(confFile) == 0){
		fprintf(stderr,"must give the config file!\n");
		exit(-2);
	}

	if(checkConfig(confFile) != 0){
		exit(-3);
	}

	*/
	
	return Utils::daemonStart();
}

 int Utils::daemonStart(){
 	struct sigaction sa;	
	sigset_t sset;		
	memset(&sa, 0, sizeof(sa));	
	sa.sa_handler = sigterm_handler;	
	sigaction(SIGINT, &sa, NULL);	
	sigaction(SIGTERM, &sa, NULL);	
	sigaction(SIGQUIT, &sa, NULL);	
	sigaction(SIGHUP, &sa, NULL);
	
	signal(SIGPIPE,SIG_IGN);		
	signal(SIGCHLD,SIG_IGN);	
	
	sigemptyset(&sset);	
	sigaddset(&sset, SIGSEGV);	
	sigaddset(&sset, SIGBUS);	
	sigaddset(&sset, SIGABRT);	
	sigaddset(&sset, SIGILL);	
	sigaddset(&sset, SIGCHLD);	
	sigaddset(&sset, SIGFPE);	
	sigprocmask(SIG_UNBLOCK, &sset, &sset);		

	//return 0;
	return background ? daemon (1, 1) : 0;
}

void* Utils::timerThread(void*){
	while(!stop){
		sleep(1);
		Utils::timerFlag = 1;
		//LOG_DEBUG("set time flag to 1");
	}
	LOG_INFO("timer thread stopped safety");

	return NULL;
}

 void Utils::startTimer(){
	pthread_t tid;
	pthread_attr_t attr;
	pthread_attr_init(&attr);

	if(pthread_create (&tid, &attr, Utils::timerThread, NULL) != 0){
		LOG_ERROR("create timer thread failed-%m");
		exit(2);
	}
 }

std::string Utils::b2s(const char *ptr, size_t nbytes,int32_t line_len){
	std::string hex_string;
	for(unsigned int i = 0; i < nbytes; i++)
	{
		if(i > 0 && i % line_len == 0)
		{
			hex_string += '[';	
			for(unsigned int j=i-line_len; j < i; j++)
			{
				char chr = *((char*)ptr+j); 
				if(isprint(chr))
					hex_string += chr;
				else
					hex_string += '.';
			}
			
			hex_string += "]\n";

		}

		char chr[3] = {0};

		sprintf(chr, "%02x ", (unsigned char)(*((char*)ptr+i)));
		hex_string += string(chr);
	}

	
	int left = nbytes % line_len;
	for(int i=line_len-left;i>0;i--)
	{
                hex_string += "   ";
	}

	if(left < line_len)
	{
		//hex_string += "    ";
		hex_string += "[";


		for(unsigned int j=nbytes-left; j < nbytes; j++)
                {
                     char chr = *((char*)ptr+j);
                     if(isprint(chr))
               		      hex_string += chr;
                     else
                        hex_string += '.';
                }
		hex_string += ']';
	}

	hex_string += '\n';
	return hex_string;
}


unsigned int Utils::getMaxMapPageCount()
{
	FILE* fp = fopen("/proc/sys/vm/max_map_count","r");
	if(!fp){
		LOG_WARNING("open file /proc/sys/vm/max_map_count failed:%m");
		return 65536;
	}

	unsigned int val = 0;
	fscanf(fp,"%u",&val);

	fclose(fp);

	return val;
}

unsigned int Utils::getCurSharePageCount(){
	char buf[512] = {0};
	sprintf(buf,"/proc/%u/statm",getpid());
	FILE* fp = fopen(buf,"r");
	if(!fp){
		LOG_WARNING("open file %s failed:%m",buf);
		return 0;
	}

	unsigned int v1,v2,mc=0;
	fscanf(fp,"%u %u %u",&v1,&v2,&mc);
	fclose(fp);

	return mc;
}

